今天來研究一下 slots的用法
參考W3School Vue的說明
Vue v-slot
https://www.w3schools.com/vue/vue_v-slot.php
slots 的概念可以想成是要將在父元件 component
的內容傳送到 component
的本身
之前是 是將父元件中的component的屬性傳送到子元件,再回傳 子元件的<template>
的內容回到父元件。
這時如果要較多的網頁內容的話,可以將slot當作是設定好的樣版,
這時傳送要組合的部份內容到子元件的<slot>
元素中,就可以回傳完整的網頁內容了
來看一下範例
main.js
import { createApp } from 'vue'
import App from './App.vue'
import SlotComp from './components/SlotComp.vue'
const app = createApp(App)
app.component('slot-comp', SlotComp)
app.mount('#app')
先看到import SlotComp from './components/SlotComp.vue' app.component('slot-comp', SlotComp)
SlotComp -> 'slot-comp'
App.vue
<template>
<h1>App.vue</h1>
<p>The component has two <div> tags with one <slot> in each.</p>
<slot-comp v-slot:default>'Default slot'</slot-comp>
</template>
<script></script>
<style>
#app {
width: 300px;
}
</style>
接著看到 <slot-comp v-slot:default>'Default slot'</slot-comp>
透過 v-slot:default
來跟 子元件的 <slot></slot>
綁定
若是 v-slot:bottomSlot
則是 跟子元件的 <slot name="bottomSlot"></slot>
綁定
接著是 <slot-comp v-slot:default>'Default slot'</slot-comp>
代表 將內容 'Default slot'
傳到 <slot></slot>
中
SlotComp.vue
<template>
<h3>Component</h3>
<div>
<slot></slot>
</div>
<div>
<slot name="bottomSlot"></slot>
</div>
</template>
<script></script>
<style scoped>
div {
height: 30px;
width: 50%;
border: dotted black 1px;
margin: 10px;
padding: 10px;
background-color: lightgreen;
font-weight: bold;
}
</style>
最後的結果是
<div id="app" data-v-app="">
<h1>App.vue</h1>
<p>The component has two <div> tags with one <slot> in each.</p>
<h3 data-v-c9ce8e5e="">Component</h3>
<div data-v-c9ce8e5e="">'Default slot'</div>
<div data-v-c9ce8e5e=""></div>
</div>
<slot-comp v-slot:default>'Default slot'</slot-comp>
轉換後
<h3 data-v-c9ce8e5e="">Component</h3>
<div data-v-c9ce8e5e="">'Default slot'</div>
<div data-v-c9ce8e5e=""></div>
//-----------------------------------------
再看一下另一個範例
App.vue
<template>
<h1>App.vue</h1>
<p>The component has two div tags with one slot in each.</p>
<slot-comp>
<template v-slot:bottomSlot>
<h4>To the bottom slot!</h4>
<p>This p tag and the h4 tag above are directed to the bottom slot with the v-slot directive used on the template tag.</p>
</template>
<p>This goes into the default slot</p>
</slot-comp>
</template>
SlotComp.vue
<template>
<h3>Component</h3>
<div>
<slot></slot>
</div>
<div>
<slot name="bottomSlot"></slot>
</div>
</template>
最後的輸出是
<div id="app" data-v-app="">
<h1>App.vue</h1>
<p>The component has two div tags with one slot in each.</p>
<h3 data-v-66527a85="">Component</h3>
<div data-v-66527a85="">
<p>This goes into the default slot</p>
</div>
<div data-v-66527a85="">
<h4>To the bottom slot!</h4>
<p>This p tag and the h4 tag above are directed to the bottom slot with the v-slot directive used on the template tag.</p>
</div>
</div>
由以上 可看出 <p>This goes into the default slot</p>
對應到 <slot></slot>
<template v-slot:bottomSlot>
<h4>To the bottom slot!</h4>
<p>This p tag and the h4 tag above are directed to the bottom slot with the v-slot directive used on the template tag.</p>
</template>
對應到 <slot name="bottomSlot"></slot>
整理一下,可以這樣來解讀
<slot-comp> </slot-comp>
引入
<h3>Component</h3>
<div>
<slot></slot>
</div>
<div>
<slot name="bottomSlot"></slot>
</div>
在 <slot-comp>
中的內容可看成是要傳入的內容<slot-comp> 要傳入的內容 </slot-comp>
其中 將 <template v-slot:bottomSlot>
的部份 傳到 <slot name="bottomSlot"></slot>
<p>This goes into the default slot</p>
傳到 <slot></slot>
因此,在 <slot-comp>
中的內容,並不是排版的順序,只是內容的範圍
<slot-comp>
<template v-slot:bottomSlot>
<h4>To the bottom slot!</h4>
<p>This p tag and the h4 tag above are directed to the bottom slot with the v-slot directive used on the template tag.</p>
</template>
<p>This goes into the default slot</p>
</slot-comp>
若改成
<slot-comp>
<template v-slot:bottomSlot> //-- bottomSlot slot
<h4>To the bottom slot!</h4>
<p>This p tag and the h4 tag above are directed to the bottom slot with the v-slot directive used on the template tag.</p>
</template>
<template> //-- default slot
<p>This goes into the default slot</p>
</template>
</slot-comp>
就會比較清楚
整理一下 slot的寫法
<slot-comp v-slot:default> -> <slot></slot>
<slot-comp v-slot:bottomSlot> -> <slot name="bottomSlot"></slot>
<slot-comp>
<template v-slot:bottomSlot>
</template>
</slot-comp>
slot 的簡約寫法
<slot-comp>
<slot-comp #bottomSlot>
<slot-comp>
<template #bottomSlot>
</template>
</slot-comp>
v-slot:bottomSlot -> #bottomSlot
v-on:click -> @click
v-bind:src -> :src
v-mode:value -> 無簡約寫法
//-------
最後再看一個範例
App.vue
<template>
<h1>Scoped Slots</h1>
<p>App.vue controls how local data from the scoped slot is rendered.</p>
<hr>
<slot-comp v-slot="texts">
<h2>{{ texts.staticText }}</h2>
<p class="greenP">{{ texts.dynamicText }}</p>
</slot-comp>
</template>
SlotComp.vue
<template>
<slot
staticText="This text is static"
:dynamicText="text"
></slot>
</template>
<script>
export default {
data() {
return {
text: 'This text is from the data property'
}
}
}
</script>
在App.vue
<slot-comp v-slot="texts">
<h2>{{ texts.staticText }}</h2>
<p class="greenP">{{ texts.dynamicText }}</p>
</slot-comp>
在SlotComp.vue<slot staticText="This text is static" :dynamicText="text"></slot>
合併後為
<div id="app" data-v-app="">
<h1>Scoped Slots</h1>
<p>App.vue controls how local data from the scoped slot is rendered.</p>
<hr>
<h2>This text is static</h2>
<p class="greenP">This text is from the data property</p>
</div>
<slot staticText="This text is static" :dynamicText="text"></slot>
這是 代表回傳的變數為 staticText, :dynamicText
同時 :dynamicText
綁定到 text
傳送回 <slot-comp v-slot="texts">
用 texts
變數來接收資料
texts.staticText, texts.dynamicText
最後 顯示到 {{ texts.staticText }},{{ texts.dynamicText }}
//-------------------------------
還是要整理一下
父元件
<slot-comp v-slot:bottomSlot> -> <slot-comp #bottomSlot>
<slot-comp v-slot:bottomSlot="texts"> -> <slot-comp #bottomSlot="texts">
<slot-comp v-slot="texts">
<slot-comp>
<template v-slot:bottomSlot></template>
</slot-comp>
子元件<slot name="bottomSlot"></slot>
這個是名稱設定為 bottomSlot 的slot
有關 slot 的部份,
因為整個流程 像是來回的內容綁定,連動,很容易造成混淆,
在使用上要很清楚之間的關係
可以先從簡單的寫法,再擴展成複雜的寫法
//-------------------------
這個範例可以釐清一些想法
App.vue
<slot-comp v-slot="food">
<h2>{{ food.key+", "+food.fname }}</h2>
</slot-comp>
SlotComp.vue
<slot :key="i" :fname="x" v-for="(x, i) in foods"></slot>
data() {
return {
foods: ['Apple','Pizza','Rice','Fish']
}
}
其中<slot :key="i" :fname="x" v-for="(x, i) in foods"></slot>
會變成
<slot key="0" fname="Apple"></slot>
<slot key="1" fname="Pizza"></slot>
<slot key="2" fname="Rice"></slot>
<slot key="3" fname="Fish"></slot>
<slot-comp v-slot="food">
會作用到每一個 <slot>
上
<slot>
的屬性回傳回<slot-comp>
的變數 food
然後呈現在 <h2>{{ food.key+", "+food.fname }}</h2>
最後變成
<h2>0, Apple</h2>
<h2>1, Pizza</h2>
<h2>2, Rice</h2>
<h2>3, Fish</h2>
所以可以看作是
<slot-comp v-slot="food">
<h2>{{ food.key+", "+food.fname }}</h2>
</slot-comp>
其中 food
用來讀取 <slot key="0" fname="Apple"></slot>
上的 屬性
若是 <slot key="0" fname="Apple"></slot>
本身沒有內容,就會是將
屬性 key="0" fname="Apple"
傳回 <slot-comp v-slot="food">
另外一種是 <slot-comp v-slot="food"></slot-comp>
本身沒有內容
<slot key="0" fname="Apple">ABCDE</slot>
這時 <slot-comp>
呈現的就是 <slot>
的內容
若是<slot-comp>
要傳給 <slot>
資料的話,語法就是
App.vue
<slot-comp foodName="Apple" fid="0"></slot-comp>
<slot-comp foodName="Pizza" fid="1"></slot-comp>
<slot-comp foodName="Rice" fid="2"></slot-comp>
<slot-comp foodName="Fish" fid="3"></slot-comp>
SlotComp.vue
<slot><h2>{{ fid+", "+foodName }}</h2></slot>
props: ['foodName','fid']
同樣也得到
<h2>0, Apple</h2>
<h2>1, Pizza</h2>
<h2>2, Rice</h2>
<h2>3, Fish</h2>
結論就是Vue提供了元件之間不同資料傳送的方式
以及產生多個元件的方式,
漸漸地要進入活用的練習了。